import streamlit as st
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
from config.matplotlib_config import apply_matplotlib_cn


apply_matplotlib_cn()

st.set_page_config(page_title="逻辑回归", page_icon="⚪")

if not st.session_state.get('logged_in', False):
    st.warning("请先在首页登录以访问此内容")
    st.stop()

st.title("逻辑回归算法")

tab1, tab2, tab3 = st.tabs(["原理讲解", "代码示例", "试一试"])

with tab1:
    st.header("逻辑回归算法原理")
    st.markdown("""
        逻辑回归是一种用于解决二分类问题的统计方法，通过逻辑函数将线性回归的输出映射到0和1之间。

        ### 数学模型
        逻辑函数(Sigmoid函数)：$\\sigma(z) = \\frac{1}{1 + e^{-z}}$

        其中 $z = \\beta_0 + \\beta_1x_1 + \\beta_2x_2 + ... + \\beta_nx_n$

        ### 决策边界
        当 $\\sigma(z) \\geq 0.5$ 时，预测为正类(1)
        当 $\\sigma(z) < 0.5$ 时，预测为负类(0)

        ### 参数估计
        最大似然估计：通过最大化似然函数来估计参数

        ### 优缺点
        **优点**：
        - 输出具有概率意义
        - 计算效率高
        - 可解释性强

        **缺点**：
        - 假设特征与log(odds)是线性关系
        - 对多重共线性敏感
        - 容易欠拟合
        """)

with tab2:
    st.header("逻辑回归代码示例")
    st.code(
        """
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report

# 生成分类数据
X, y = make_classification(n_samples=100, n_features=2, n_redundant=0, 
                          n_informative=2, random_state=42)

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 创建逻辑回归模型
model = LogisticRegression()

# 训练模型
model.fit(X_train, y_train)

# 预测
y_pred = model.predict(X_test)
y_pred_proba = model.predict_proba(X_test)[:, 1]

# 评估模型
accuracy = accuracy_score(y_test, y_pred)
print(f"准确率: {accuracy:.2f}")
print("混淆矩阵:")
print(confusion_matrix(y_test, y_pred))
print("分类报告:")
print(classification_report(y_test, y_pred))
        """,
        language="python",
    )

with tab3:
    st.header("逻辑回归演示")

    X, y = make_classification(
        n_samples=200,
        n_features=2,
        n_redundant=0,
        n_informative=2,
        n_clusters_per_class=1,
        random_state=42,
    )
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.3, random_state=42
    )

    col1, col2 = st.columns(2)

    with col1:
        penalty = st.selectbox("正则化类型", ["l1", "l2", "elasticnet", "none"])
        C_value = st.slider("正则化强度C", 0.01, 10.0, 1.0)

        if penalty == "elasticnet":
            l1_ratio = st.slider("L1比例 (l1_ratio)", 0.0, 1.0, 0.5)
            solver = 'saga'
        else:
            l1_ratio = None
            solver = 'saga' if penalty == 'l1' else 'lbfgs'

        try:
            if penalty == "none":
                model = LogisticRegression(penalty=None, C=C_value, solver=solver, random_state=42)
            elif penalty == "elasticnet":
                model = LogisticRegression(penalty=penalty, C=C_value, l1_ratio=l1_ratio, solver=solver, random_state=42)
            else:
                model = LogisticRegression(penalty=penalty, C=C_value, solver=solver, random_state=42)

            model.fit(X_train, y_train)
            y_pred = model.predict(X_test)
            accuracy = accuracy_score(y_test, y_pred)

            st.metric("准确率", f"{accuracy:.4f}")
            st.write(f"系数: {model.coef_}")
            st.write(f"截距: {model.intercept_}")

            model_trained = True
        except Exception as e:
            st.error(f"参数组合不支持: {e}")
            model_trained = False

    with col2:
        if model_trained:
            h = 0.02
            x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
            y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
            xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))

            Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
            Z = Z.reshape(xx.shape)

            fig, ax = plt.subplots(figsize=(8, 6))
            plt.contourf(xx, yy, Z, alpha=0.4, cmap=plt.cm.RdYlBu)
            plt.scatter(X[:, 0], X[:, 1], c=y, s=20, edgecolor='k', cmap=plt.cm.RdYlBu)
            plt.title("逻辑回归决策边界")
            plt.xlabel("特征1")
            plt.ylabel("特征2")
            st.pyplot(fig)
        else:
            st.warning("请先选择有效的参数组合并成功训练模型") 